package com.sangmo.fts.training.service;

import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.common.session.UserSession;
import com.sangmo.boot.framework.plugin.dataview.crud.service.BaseViewService;
import com.sangmo.boot.framework.plugin.dataview.data.IDataViewRepo;
import com.sangmo.fts.clazz.model.Clazz;
import com.sangmo.fts.clazz.service.ClazzService;
import com.sangmo.fts.common.authority.service.AuthorityEntityService;
import com.sangmo.fts.teacher.service.ExaminationService;
import com.sangmo.fts.training.interfaces.ExaminationTeamCreation;
import com.sangmo.fts.training.interfaces.TeamCreation;
import com.sangmo.fts.training.interfaces.TeammateCreation;
import com.sangmo.fts.training.model.Team;
import com.sangmo.fts.training.model.Teammate;
import com.sangmo.fts.training.repo.TeamRepo;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Transactional
public class TeamEntityService extends AuthorityEntityService<Team> {

    @Autowired
    private TeamRepo teamRepo;

    @Autowired
    private TeammateEntityService teammateEntityService;

    @Autowired
    private ClazzService clazzService;

    @Autowired
    private ExaminationService examinationService;

    @Override
    protected IDataViewRepo<Team> getRepo() {
        return teamRepo;
    }

    @Override
    protected void onCreate(Team entity, Object bo) {
        super.onCreate(entity, bo);
        Long currentUserId = (Long) UserSession.getUserInterface().getId();
        Clazz clazz = clazzService.findByStudentId(currentUserId);
        checkIfExists(currentUserId, bo);
        validateTeammates(currentUserId, bo, clazz);
        entity.setClazzId(clazz.getId());
    }


    @Override
    protected void afterCreated(Team entity, Object bo) {
        super.afterCreated(entity, bo);
        List<TeammateCreation> teammateCreations = null;
        if (bo instanceof TeamCreation) {
            teammateCreations = ((TeamCreation)bo).getTeammates();
        } else if (bo instanceof ExaminationTeamCreation) {
            teammateCreations = ((ExaminationTeamCreation)bo).getTeammates();
        }
        for (TeammateCreation tc : teammateCreations) {
            Teammate teammate = new Teammate();
            teammate.setTeamId(entity.getId());
            teammate.setUserId(tc.getUserId());
            teammate.setRole(tc.getRole());
            teammateEntityService.save(teammate);
        }
    }

    private void checkIfExists(Long userId, Object bo) {
        if (bo instanceof TeamCreation) {
            List<Team> teams = teamRepo.findByCreatedByAndBusinessTypeAndEndTimeGreaterThanAndExaminationIdIsNull(userId, ((TeamCreation) bo).getBusinessType(), new Date());
            if (CollectionUtils.isNotEmpty(teams)) {
                throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.team.exists.create.disabled");
            }
        } else if (bo instanceof ExaminationTeamCreation) {
            List<Team> teams = teamRepo.findByCreatedByAndExaminationId(userId, ((ExaminationTeamCreation) bo).getExaminationId());
            if (CollectionUtils.isNotEmpty(teams)) {
                throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.team.exists.create.disabled");
            }
        }
    }

    private void validateTeammates(Long currentUserId, Object bo, Clazz clazz) {
        List<TeammateCreation> teammates = null;
        String businessType = null;
        if (bo instanceof TeamCreation) {
            TeamCreation tc = (TeamCreation)bo;
            businessType = tc.getBusinessType();
            teammates = tc.getTeammates();
        } else if (bo instanceof ExaminationTeamCreation) {
            ExaminationTeamCreation etc = (ExaminationTeamCreation)bo;
            businessType = examinationService.get(etc.getExaminationId()).getBusinessType();
            teammates = etc.getTeammates();
        }
        //校验当前用户是否在队员中
        List<Long> userIds = teammates.stream().map(TeammateCreation::getUserId).collect(Collectors.toList());
        if (!userIds.contains(currentUserId)) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.team.create.currentUser.notExist");
        }

        //校验队员是否为同一班级用户
        for (TeammateCreation teammate : teammates) {
            Clazz teammateClazz = clazzService.findByStudentId(teammate.getUserId());
            if (null == teammateClazz || !clazz.getId().equals(teammateClazz.getId())) {
                throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.team.create.teammate.notAvailable");
            }
        }

        List<String> roleList = new ArrayList<>();
        teammates.forEach(e -> {
            String[] roleArr = e.getRole().split(",");
            roleList.addAll(Stream.of(roleArr).collect(Collectors.toList()));
        });

        List<String> compliantRoles  = Teammate.businessTypeMapRoles.get(businessType);
        if (!checkDifferent(roleList, compliantRoles)) {
            throw new ServiceException(StandardErrors.EXTERNAL_ERROR.getStatus(), "error.team.create.roles.notCompliant");
        }
    }

    private static boolean checkDifferent(List<String> list, List<String> list1) {
        list.sort(Comparator.comparing(String::hashCode));
        list1.sort(Comparator.comparing(String::hashCode));
        return list.toString().equals(list1.toString());
    }

    private void checkValid(Long userId, List<TeammateCreation> teammates) {

    }
}
